#include <iostream>
#include <fstream>
#include <driver.h>
#include <Context.h>
#include <BackendI.h>
#include <unistd.h>
#include <stdlib.h>
#include <vector>
#include <sstream>

using namespace std;

void printUsage(vector<string>& formats, string appName);

int main(int argc, char ** argv)

{
  int option;
  opterr = 0;

  // Flag para generar archivo .dot
  bool genDotFile = false;

  // Flag para generar informacion de depuracion en el nivel lexico.
  bool lexDebug = false;

  // Flag para generar informacion de depuracion en el nivel sintactico.
  bool parserDebug = false;

  bool error = false;

  // Formato por defecto png
  string outFormat = string("png");

  string inputFile = "";

  // Formatos de salida permitidos.
  vector<string> outFormats;
  outFormats.push_back("canon");
  outFormats.push_back("cmap");
  outFormats.push_back("cmapx");
  outFormats.push_back("cmapx_np");
  outFormats.push_back("dot");
  outFormats.push_back("eps");
  outFormats.push_back("fig");
  outFormats.push_back("gd");
  outFormats.push_back("gd2");
  outFormats.push_back("gif");
  outFormats.push_back("gv");
  outFormats.push_back("imap");
  outFormats.push_back("imap_np");
  outFormats.push_back("ismap");
  outFormats.push_back("jpe");
  outFormats.push_back("jpeg");
  outFormats.push_back("jpg");
  outFormats.push_back("pdf");
  outFormats.push_back("plain");
  outFormats.push_back("plain-ext");
  outFormats.push_back("png");
  outFormats.push_back("ps");
  outFormats.push_back("ps2");
  outFormats.push_back("svg");
  outFormats.push_back("svgz");
  outFormats.push_back("tk");
  outFormats.push_back("vml");
  outFormats.push_back("vmlz");
  outFormats.push_back("vrml");
  outFormats.push_back("wbmp");
  outFormats.push_back("x11");
  outFormats.push_back("xdot");
  outFormats.push_back("xlib");
  
  vector<string>::iterator it;
  bool found = false;

  if(argc < 2) {

    printUsage(outFormats, string(argv[0]));
    exit(1);
  }

  while((option = getopt(argc, argv, "-dpsf:")) != -1){

    switch(option) {
    
    case 'p':
      parserDebug = true;
      break;
      
    case 's':
      lexDebug = true;
      break;
      
    case 'd':
      // Se genera archivo .dot a la salida.
      genDotFile = true;
      break;

    case 'f':
      // Formato de la salida.
      outFormat = string(optarg);
      it = outFormats.begin();
      while(!found && it != outFormats.end()){
	if (*(it++) == outFormat)
	  found = true;
      }

      if(!found){
	ostringstream errStream;
	cerr << "Output format \'" << outFormat << "\' not allowed." << endl;
	error = true;
      }
      break;

    case 1:
      inputFile = string(optarg);
      break;

    case '?':
      if(isprint(optopt)) {
	if(optopt == 'f') {
	  cerr << "Output format not especified." << endl;
	} else {
	  char invalidOpt = static_cast<char>(optopt);
	  cerr << "Unknown option -" << invalidOpt << endl;
	}
      } else {
	cerr << "Unknown option caracter " << optopt << endl;
      }
      error = true;
      break;
    }
  }

  if(error || inputFile == ""){
    printUsage(outFormats, string(argv[0]));
    exit(1);
  }

  netthumb::SymbolTable stable;
  netthumb::ContextI context(stable);
  netthumb::Driver driver(context);

  driver.trace_parsing = lexDebug;
  driver.trace_scanning = parserDebug;

  bool result = driver.parse_file(inputFile);
  if(stable.isValid()) {
    netthumb::BackendI backend(inputFile, outFormat, stable);
    backend.makeGraph();

    if(genDotFile){
      // Genera el archivo .dot de salida
      int infIndex = inputFile.find_last_of("/") == string::npos ? 0 : inputFile.find_last_of("/") + 1;
      string dotFileName = inputFile.substr(infIndex, inputFile.size() - infIndex);
      backend.genCmdFile(dotFileName.substr(0, dotFileName.find_first_of(".")) + ".dot");
    }

  } else {
    cerr << inputFile << " contains errors" << endl;
    exit(1);
  }

  exit(0);
}

void printUsage(vector<string>& formats, string appName)
{

  vector<string>::iterator it;
  cerr << "Usage: " << appName << " [-d] [-s] [-p] [-f FORMAT] fileInput" << endl;
  cerr << "Where:" << endl << "\t-d option generate a dot file for use as input for " << GRAPH_CMD << endl;
  cerr << "\t-s option shows lexer debug information" << endl;
  cerr << "\t-p option shows sintactic debug information" << endl;
  cerr << "\t-f option defines the output format among ";
  
  ostringstream errStream;
  for(it = formats.begin(); it != formats.end(); it++){
    errStream << *it << ", ";
  }
  cerr << errStream.str().substr(0, errStream.str().size()-2) << endl;
  cerr << "\tfileInput is the file with the net definition" << endl;
}
